package com.drg.center.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.drg.center.dao.SysRoleDAO;
import com.drg.center.dao.SysRoleResourcesDAO;
import com.drg.center.entity.param.SysRoleAddDTO;
import com.drg.center.entity.param.SysRoleEditDTO;
import com.drg.center.entity.param.SysRoleListDTO;
import com.drg.center.entity.result.SysRoleVO;
import com.google.common.collect.Maps;
import com.guaike.core.entity.constant.ViewConstant;
import com.guaike.core.entity.exception.ApiException;
import com.guaike.core.entity.result.PageEntity;
import com.guaike.core.entity.result.Result;
import com.guaike.core.utils.ListUtil;
import com.drg.center.dao.SysResourcesDAO;
import com.drg.center.dao.SysUserRoleDAO;
import com.drg.center.entity.SysResourcesPO;
import com.drg.center.entity.SysRolePO;
import com.drg.center.entity.SysRoleResourcesPO;
import com.drg.center.entity.SysUserRolePO;
import com.drg.center.service.SysRoleService;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.mockito.internal.util.collections.Sets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: zhangxilin
 * @Date: 2024/5/21
 */
@Slf4j
@Service
public class SysRoleServiceImpl implements SysRoleService {

    @Autowired
    private SysRoleDAO sysRoleDAO;
    @Autowired
    private SysRoleResourcesDAO sysRoleResourcesDAO;
    @Autowired
    private SysResourcesDAO sysResourcesDAO;
    @Autowired
    private SysUserRoleDAO sysUserRoleDAO;


    @Autowired
    private DataSourceTransactionManager transactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;

    @Override
    public Result<PageEntity<SysRoleVO>> findPage(SysRoleListDTO param) {
        IPage<SysRolePO> iPage = sysRoleDAO.findPage(param);
        if(CollectionUtils.isEmpty(iPage.getRecords())){
            return Result.success().data(new PageEntity<>(iPage.getTotal(), Lists.newArrayList())).build();
        }
        List<SysRoleVO> list = ListUtil.copyList(iPage.getRecords(), SysRoleVO.class);
        return Result.success().data(new PageEntity<>(iPage.getTotal(), list)).build();
    }

    @Override
    public Result<List<SysRoleVO>> all() {
        List<SysRoleVO> list = Lists.newArrayList();
        List<SysRolePO> poList = sysRoleDAO.findAll();
        if(CollectionUtils.isEmpty(poList)){
            return Result.success().data(list).build();
        }
        list = ListUtil.copyList(poList, SysRoleVO.class);
        return Result.success().data(list).build();
    }

    @Override
    public Result<SysRoleVO> detail(Long id) {
        SysRolePO  record =  sysRoleDAO.findById(id);
        if(record == null){
            return Result.failure().message("记录不存在").build();
        }
        Map<String, Set<Long>> resMap = Maps.newHashMap();
        List<SysRoleResourcesPO> resourcesPOList = sysRoleResourcesDAO.findList(SysRoleResourcesPO::getRoleId, id);
        if(!CollectionUtils.isEmpty(resourcesPOList)){
           List<Long> resIdList= resourcesPOList.stream().map(SysRoleResourcesPO::getResId).collect(Collectors.toList());
           List<SysResourcesPO> poList = sysResourcesDAO.findByIdList(resIdList);
           for(SysResourcesPO po: poList){
               Set<Long> resSet = resMap.get(po.getSysCode());
               if(CollectionUtils.isEmpty(resSet)){
                   resSet = new HashSet<>();
               }
               resSet.add(po.getId());
               resMap.put(po.getSysCode(), resSet);
           }
        }

        SysRoleVO vo = new SysRoleVO();
        BeanUtil.copyProperties(record, vo);
        vo.setResMap(resMap);
        return Result.success().data(vo).build();
    }

    @Override
    public Result<Boolean> add(SysRoleAddDTO param) {
        if(sysRoleDAO.isExist(param.getRoleName(), null)){
            return Result.failure().message("角色名称已存在").build();
        }
        SysRolePO record = new SysRolePO();
        record.setRoleName(param.getRoleName());
        record.setDescription(param.getDescription());
        record.setRemark(param.getRemark());

        Set<Long> resIdSet = getResIdSet(param.getResIdList());

        TransactionStatus transactionStatus= transactionManager.getTransaction(transactionDefinition);
        try{
            sysRoleDAO.save(record);

            if(!CollectionUtils.isEmpty(resIdSet)){
                List<SysRoleResourcesPO> roleResourcesPOList = Lists.newArrayList();
                resIdSet.forEach(resId -> {
                    SysRoleResourcesPO roleResourcesPO = new SysRoleResourcesPO();
                    roleResourcesPO.setRoleId(record.getId());
                    roleResourcesPO.setResId(resId);
                    roleResourcesPOList.add(roleResourcesPO);
                });
                sysRoleResourcesDAO.saveBatch(roleResourcesPOList);
            }
            transactionManager.commit(transactionStatus);
        }catch (Exception e){
            log.error("执行事务异常，需要回滚 e:{}",e);
            transactionManager.rollback(transactionStatus);
            throw new ApiException(e.getMessage());
        }
        return Result.success().data(Boolean.TRUE).build();
    }

    @Override
    public Result<Boolean> edit(SysRoleEditDTO param) {
        if(sysRoleDAO.isExist(param.getRoleName(), param.getId())){
            return Result.failure().message("角色名称已存在").build();
        }
        SysRolePO record = sysRoleDAO.findById(param.getId());
        if(record == null){
            return Result.failure().message("记录不存在").build();
        }
        record.setRoleName(param.getRoleName());
        record.setDescription(param.getDescription());
        record.setRemark(param.getRemark());

        Set<Long> resIdSet = getResIdSet(param.getResIdList());
        List<SysRoleResourcesPO> roleResourcesPOList = Lists.newArrayList();
        if(!CollectionUtils.isEmpty(resIdSet)){
            resIdSet.forEach(resId -> {
                SysRoleResourcesPO roleResourcesPO = new SysRoleResourcesPO();
                roleResourcesPO.setRoleId(record.getId());
                roleResourcesPO.setResId(resId);
                roleResourcesPOList.add(roleResourcesPO);
            });
        }

        TransactionStatus transactionStatus= transactionManager.getTransaction(transactionDefinition);
        try{
            sysRoleDAO.updateById(record);
            sysRoleResourcesDAO.del(SysRoleResourcesPO::getRoleId, param.getId());
            if(!CollectionUtils.isEmpty(resIdSet)){
                sysRoleResourcesDAO.saveBatch(roleResourcesPOList);
            }
            transactionManager.commit(transactionStatus);
        }catch (Exception e){
            log.error("执行事务异常，需要回滚 e:{}",e);
            transactionManager.rollback(transactionStatus);
            throw new ApiException(e.getMessage());
        }
        return Result.success().data(Boolean.TRUE).build();
    }

    private Set<Long> getResIdSet(Set<Long> resIdSet){
        if(CollectionUtils.isEmpty(resIdSet)){
            return null;
        }
        List<SysResourcesPO> poList = sysResourcesDAO.findByIdList(resIdSet);
        if(CollectionUtils.isEmpty(poList)){
            return null;
        }
        Set<Long> idSet = new HashSet<>();
        for(SysResourcesPO po: poList){
            idSet.add(po.getId());
            if(StringUtil.isBlank(po.getTraceIds())){
                continue;
            }
            List<String> idList = Arrays.asList(po.getTraceIds().split(ViewConstant.COMMA_DISP));
            Set<Long>  resUidLong = idList.stream().map(Long::valueOf).collect(Collectors.toSet());
            idSet.addAll(resUidLong);
        }
        return idSet;
    }

    @Override
    public Result<Boolean> delete(Long id) {
        SysRolePO record = sysRoleDAO.findById(id);
        if(record == null){
            return Result.failure().message("记录不存在").build();
        }
        TransactionStatus transactionStatus= transactionManager.getTransaction(transactionDefinition);
        try{
            sysRoleDAO.del(id);
            sysRoleResourcesDAO.del(SysRoleResourcesPO::getRoleId, id);
            sysUserRoleDAO.del(SysUserRolePO::getRoleId, id);
            transactionManager.commit(transactionStatus);
        }catch (Exception e){
            log.error("执行事务异常，需要回滚 e:{}",e);
            transactionManager.rollback(transactionStatus);
            throw new ApiException(e.getMessage());
        }
        return Result.success().data(Boolean.TRUE).build();
    }
}
